1. Problem
You are building a solution
that must execute business rules based on dynamic information. These
business rules are likely to change over time, and you want to minimize
the impact on the solution when modifications are needed. To do this,
you want to be able to call the rules engine from a .NET assembly.
2. Solution
This solution describes
the steps necessary to call the business rules engine from a C#
assembly. The steps detail how to build a .NET Windows application to
process job applications and dynamically determine whether applicants
meet a minimum age requirement. If the applicant is younger than a
certain age, that person cannot be considered for employment. The
minimum age is likely to change over time and needs to be easily
configurable. The business rules engine that comes with BizTalk Server
captures the business rule determining the minimum working age.
This solution assumes that
a rule exists in the business rules engine to determine whether an
applicant meets the minimum age requirements. To call this rule from a
.NET application, follow these steps:
Open the project containing the .NET application.
Add a project reference to the Microsoft.RuleEngine.dll assembly, which contains the classes required to call the business rules engine. This may be in either $\Program Files\Common Files\Microsoft BizTalk or $\Program Files\Microsoft BizTalk Server 2010\.
Create the necessary policy and fact objects, and execute the business rule policy.
Example 1. Calling a Business Rule from .NET
public void callSamplePolicy(ref System.Xml.XmlDocument newHireListDoc) { // create the SamplePolicy policy object // specify policy name and version Microsoft.RuleEngine.Policy policy = new Microsoft.RuleEngine.Policy("SamplePolicy", 1, 0);
// create the facts object array to hold the input parameters for the policy object[] facts = new object[1];
// create the input parameter for the SamplePolicy policy // based on a typed BizTalk schema (fully qualified .NET type) Microsoft.RuleEngine.TypedXmlDocument typedXmlDoc = new Microsoft.RuleEngine.TypedXmlDocument("SampleSolution.NewHireList", newHireListDoc);
// add the input parameter to the facts object array facts[0] = typedXmlDoc;
// execute the policy against the facts policy.Execute(facts); policy.Dispose();
// set the parameter object newHireListDoc.LoadXml(typedXmlDoc.Document.OuterXml); }
|
3. How It Works
Although the business
rules engine comes as part of BizTalk Server, this solution shows that
.NET assemblies outside the BizTalk environment can call into it. This
allows external applications to use the same rule framework that the
integration hub does, enabling companies to consolidate their business
rules functionality onto one platform.
NOTE
You can extend this solution
by using a web/WCF service method to access the business rules engine,
allowing code on any platform to call into a common rule framework.
4. Executing a Policy
For a .NET project to call into the business rules engine, it must reference the Microsoft.RuleEngine.dll
assembly. This assembly contains the classes used to access the rules
framework, including those to execute policies. In this solution, you
first create an instance of the policy object, with the appropriate name
and version. The name must exactly match the name of the policy you
want to execute. This solution specifies SamplePolicy as the policy name, which maps to the highlighted name in Figure 1.
Following the policy name,
you specify the major and minor versions of the policy you want to
execute. You specify 1.0, which is the only version of the policy
currently deployed. Alternatively, you could specify the name only when
creating the policy object (no version parameters supplied to the
policy's constructor method), which executes the most recently deployed
version of the policy.
Next, you create a collection
(array) of fact objects. This array holds all the objects necessary to
execute the policy. These objects map to the different types of facts
that the Business Rule Composer can create, including XML documents,
.NET classes or class members, and database connections. The SamplePolicy policy uses only a single XML document fact, which you create next.
You use the Microsoft.RuleEngine.TypedXmlDocument
class to create an XML document fact, specifying the document type (the
fully qualified .NET type name) and XML document instance. Add this TypedXmlDocument to the fact collection.
Finally, you execute the policy against the facts collection. The facts collection is passed as a reference
parameter, meaning any changes to the facts will be committed to the
original instances. In this solution, the XML document fact will have
the appropriate minimum age requirement logic applied.
It is also possible to execute a policy directly from an Expression shape within an orchestration.
Example 2. Calling Policy from Expression Shape
// create the SamplePolicy policy object // policy variable has type of Microsoft.RuleEngine.Policy. Create this in Orchestration View Variables policy = new Microsoft.RuleEngine.Policy("SamplePolicy", 1, 0);
// create the input parameter for the OrderShipping policy // typedXmlDoc variable has type of Microsoft.RuleEngine.TypedXmlDocument // NewHireListMessage has type of SampleSolution.NewHireList typedXmlDoc = new Microsoft.RuleEngine.TypedXmlDocument("SampleSolution.NewHireList", NewHireListMessage);
// execute the policy against the facts policy.Execute(typedXmlDoc); policy.Dispose();
|
Although the policy executed in
this recipe requires only a single XML document fact, facts can also be
.NET classes or class members and data connections. By default, BizTalk
Server requires you to provide an object instance for each fact used in
a policy.
5. Passing Data Connection Facts
To pass a data connection fact to a policy, initialize a Microsoft.RuleEngine.DataConnection
instance and pass it to the policy in the facts collection. If an
update is being executed against the underlying database, you must also
provide a transaction to the DataConnection object, as shown in Listing 7-9. If data is being retrieved only, no transaction is required.
Example 3. Providing a Transaction
// create SQL connection object sqlConnection = new System.Data.SqlClient.SqlConnection("ConnectionString");
// create SQL transaction object sqlTransaction = sqlConnection.BeginTransaction();
// create Data Connection object dataConnection = new Microsoft.RuleEngine.DataConnection( "SqlDataSetName", "SqlTableName", sqlConnection, sqlTransaction);
|
The .NET assembly can add this DataConnection object instance to a fact collection and pass it to the policy for execution.